/*
 * Copyright (c) 2024. hallele, Inc All rights reserved.
 */

package cn.hallele.ms.filecenter.integration.action.minio;

import cn.hallele.infrastructure.metadata.constant.MsgCodeConst;
import cn.hallele.infrastructure.metadata.constant.SymbolConstant;
import cn.hallele.infrastructure.metadata.exception.children.SensitiveException;
import cn.hallele.infrastructure.util.FileUtil;
import cn.hallele.infrastructure.util.ObjectUtil;
import cn.hallele.mc.sdk.filecenter.dto.FileDTO;
import cn.hallele.ms.filecenter.integration.action.minio.config.MinioProperties;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.StatObjectArgs;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

/**
 * minio 服务,存储使用md5当名字
 *
 * @author anle5
 * @since 2024/9/22 19:34
 */
@Slf4j
@Service
public class MinioIntegrationService {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioProperties minioProperties;

    /**
     * 上传文件
     *
     * @param fileDTO minioDTO
     * @return 文件名
     */
    public String uploadFile(FileDTO fileDTO) {
        MultipartFile file = fileDTO.getMultipartFile();
        String originalFilename = file.getOriginalFilename();
        if (ObjectUtil.isBlank(originalFilename)) {
            log.error("Upload file's name is blank, file id: {}.", fileDTO.getId());
            throw new SensitiveException(MsgCodeConst.SENSITIVE_ERROR);
        }
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioProperties.getBucket())
                    .object(getFullPath(fileDTO))
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
            return getUrl(fileDTO);
        } catch (Exception e) {
            log.error("Upload file failed, filename: {}.", originalFilename, e);
            throw new SensitiveException(MsgCodeConst.SENSITIVE_ERROR);
        }
    }

    /**
     * 获取文件的url路径，供前端下载/展示
     *
     * @param fileDTO minioDTO
     * @return 文件的url路径
     */
    public String getUrl(FileDTO fileDTO) {
        String fullPath = getFullPath(fileDTO);
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .bucket(minioProperties.getBucket())
                    .object(fullPath)
                    .method(Method.GET)
                    .build());
        } catch (Exception e) {
            log.error("Get file url failed, filename: {}.", fullPath, e);
            throw new SensitiveException(MsgCodeConst.SENSITIVE_ERROR);
        }
    }

    /**
     * 获取文件的url路径，供前端下载/展示，但是有过期时间
     *
     * @param fileDTO minioDTO
     * @return url
     */
    public String getUrlWithExpires(FileDTO fileDTO) {
        String fullPath = getFullPath(fileDTO);
        try {
            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                    .expiry(fileDTO.getExpires())
                    .bucket(minioProperties.getBucket())
                    .object(fullPath)
                    .method(Method.GET)
                    .build();
            return minioClient.getPresignedObjectUrl(args);
        } catch (Exception e) {
            log.error("Get file url failed, filename: {}.", fullPath, e);
            throw new SensitiveException(MsgCodeConst.SENSITIVE_ERROR);
        }
    }

    /**
     * 获取文件信息, 如果抛出异常则说明文件不存在
     *
     * @param fileDTO minioDTO
     * @return 文件信息
     */
    public String getFileInfo(FileDTO fileDTO) {
        String fullPath = getFullPath(fileDTO);
        try {
            return minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(minioProperties.getBucket())
                            .object(fullPath)
                            .build()).toString();
        } catch (Exception e) {
            log.error("Get file info failed, filename: {}.", fullPath, e);
            throw new SensitiveException(MsgCodeConst.SENSITIVE_ERROR);
        }
    }

    /**
     * minio上命名将使用md5，可做唯一性校验
     *
     * @param fileDTO fileDTO
     * @return 全路径名
     */
    private String getFullPath(FileDTO fileDTO) {
        String filepath = fileDTO.getFilepath();
        filepath = filepath.endsWith(SymbolConstant.SLASH) ? filepath : filepath + SymbolConstant.SLASH;
        String md5 = fileDTO.getMd5();
        String fileSuffix = FileUtil.getFileSuffix(fileDTO.getFilename());
        return filepath + md5 + SymbolConstant.POINT + fileSuffix;
    }
}
